﻿using LxBasic;

namespace LxCore
{
    public class SystemFieldCenter : JsObject
    {
        //double
        public ScalarPathField Temperature { get; } = new ScalarPathField(zf => zf.Temperature);
        public VelocityMagnitudeField VelocityMagnitude { get; } = new VelocityMagnitudeField();
        public ScalarPathField Velocity_U { get; } = new ScalarPathField(zf => zf.Velocity?.U);
        public ScalarPathField Velocity_V { get; } = new ScalarPathField(zf => zf.Velocity?.V);
        public ScalarPathField Velocity_W { get; } = new ScalarPathField(zf => zf.Velocity?.W);
        public ScalarPathField Pressure { get; } = new ScalarPathField(zf => zf.Pressure);
        public DensiytField Density { get; }=new DensiytField ();
        public MassImbalanceField MassImbalance { get; } = new MassImbalanceField();
        public BoundAdjacentCellIndexField BoundAdjacentCellIndex { get; } = new BoundAdjacentCellIndexField();
        public BoundAdjacentCellPressureField BoundAdjacentCellPressure { get; } = new BoundAdjacentCellPressureField();
        //vector
        public VelocityField Velocity { get; } = new VelocityField();
        public class ScalarPathField : FieldBase<double>//TODO 处理可能出现的null
        {
            public ScalarPathField(Func<ZoneCFDFields, ScalarBase?> scalarPath)
            {
                this.ScalarPath = scalarPath;
            }
            public Func<ZoneCFDFields, ScalarBase?> ScalarPath { get; set; }
            public override ICellVarArr<double>? GetCellVarArr(IIndexHost indexHost)
            {
                ScalarBase scalar1;
                switch (indexHost)
                {
                    case FvInner inner:
                        scalar1 = ScalarPath.Invoke(ResHelper.GetField(inner.InZone));
                        return scalar1 == null ? null : new VarArrBuider.Direct<double>(scalar1.InnX);
                    case FvBound bound:
                        scalar1 = ScalarPath.Invoke(ResHelper.GetField(bound.InZone));
                        return scalar1 == null ? null : new VarArrBuider.Direct<double>(scalar1.BouX);
                    //case FvJoint joint:
                    //    break;
                    default: throw new NotImplementedException();
                }
            }
            public override IFaceVarArr<double>? GetFaceVarArr(IIndexHost indexHost)
            {
                ScalarBase scalar1;
                switch (indexHost)
                {
                    case FvInner inner:
                        scalar1 = ScalarPath.Invoke(ResHelper.GetField(inner.InZone));
                        return scalar1 == null ? null : new VarArrBuider.InnFaceByAve(inner.InZone, scalar1.InnX);
                    case FvBound bound:
                        scalar1 = ScalarPath.Invoke(ResHelper.GetField(bound.InZone));
                        return scalar1 == null ? null : new VarArrBuider.Direct<double>(scalar1.BouX);
                    //case FvJoint joint:
                    //    break;
                    default: throw new NotImplementedException();
                }
            }
        }
        public class VelocityMagnitudeField : FieldBase<double>
        {
            public override ICellVarArr<double>? GetCellVarArr(IIndexHost indexHost)
            {
                switch (indexHost)
                {
                    case FvInner inner: return ResHelper.GetField(inner.InZone)?.Velocity?.GetInnCellVelVars();
                    case FvBound bound: return ResHelper.GetField(bound.InZone)?.Velocity?.GetBouCellVelVars();
                    default: throw new NotImplementedException();
                }
            }
            public override IFaceVarArr<double>? GetFaceVarArr(IIndexHost indexHost)
            {
                SIMPLEVelocity? vel;
                switch (indexHost)
                {
                    case FvInner inn:
                        vel = ResHelper.GetField(inn.InZone)?.Velocity;
                        return vel == null ? null : new VarArrBuilder3.InnFaceAve(inn.InZone, vel.U.InnX, vel.V.InnX, vel.W.InnX);
                    case FvBound bou:
                        vel = ResHelper.GetField(bou.InZone)?.Velocity;
                        return vel == null ? null : new VarArrBuilder3.Direct(vel.U.BouX, vel.V.BouX, vel.W.BouX);
                    default: throw new NotFiniteNumberException();
                }
            }
        }
        public class VelocityField : FieldBase<Vector3d>
        {
            public override ICellVarArr<Vector3d>? GetCellVarArr(IIndexHost indexHost)
            {
                switch (indexHost)
                {
                    case FvInner inner: return ResHelper.GetField(inner.InZone)?.Velocity?.GetInnCellVelVars();
                    case FvBound bound: return ResHelper.GetField(bound.InZone)?.Velocity?.GetBouCellVelVars();
                    default: throw new NotImplementedException();
                }
            }
            public override IFaceVarArr<Vector3d>? GetFaceVarArr(IIndexHost indexHost)
            {
                SIMPLEVelocity? vel;
                switch (indexHost)
                {
                    case FvInner inn:
                        vel = ResHelper.GetField(inn.InZone)?.Velocity;
                        return vel == null ? null : new VarArrBuilder3.InnFaceAve(inn.InZone, vel.U.InnX, vel.V.InnX, vel.W.InnX);
                    case FvBound bou:
                        vel = ResHelper.GetField(bou.InZone)?.Velocity;
                        return vel == null ? null : new VarArrBuilder3.Direct(vel.U.BouX, vel.V.BouX, vel.W.BouX);
                    default: throw new NotFiniteNumberException();
                }
            }
        }
        public class DensiytField : FieldBase<double>
        {
            public override ICellVarArr<double>? GetCellVarArr(IIndexHost indexHost) => indexHost switch
            {
                FvInner inn => ResHelper.GetField(inn)?.Density?.GetInnCellVarArr(),
                FvBound bou => ResHelper.GetField(bou)?.Density?.GetBouCellVarArr(),
                _ => null,
            };
            public override IFaceVarArr<double>? GetFaceVarArr(IIndexHost indexHost) => indexHost switch
            {
                FvInner inn => ResHelper.GetField(inn)?.Density?.GetInnFaceVarArr(),
                FvBound bou => ResHelper.GetField(bou)?.Density?.GetBouFaceVarArr(),
                _ => null,
            };
        }
        public class MassImbalanceField : FieldBase<double>
        {
            public override ICellVarArr<double>? GetCellVarArr(IIndexHost indexHost)
            {
                double[]? mf;
                switch (indexHost)
                {
                    case FvInner inn:
                        mf = ResHelper.GetField(inn.InZone).MassFlux?.MassImbalance;
                        return mf == null ? null : new VarArrBuider.Direct<double>(mf);
                    case FvBound bou:
                        mf = ResHelper.GetField(bou.InZone).MassFlux?.MassImbalance;
                        return mf == null ? null : new VarArrBuider.BouCellFaceByInn<double>(bou.InZone, mf);
                    default: throw new NotImplementedException();
                }
            }
            public override IFaceVarArr<double>? GetFaceVarArr(IIndexHost indexHost)
            {
                double[]? mf;
                switch (indexHost)
                {
                    case FvInner inn:
                        mf = ResHelper.GetField(inn.InZone).MassFlux?.MassImbalance;
                        return mf == null ? null : new VarArrBuider.InnFaceByAve(inn.InZone, mf);
                    case FvBound bou:
                        mf = ResHelper.GetField(bou.InZone).MassFlux?.MassImbalance;
                        return mf == null ? null : new VarArrBuider.BouCellFaceByInn<double>(bou.InZone, mf);
                    default: return null;
                }
            }
        }
        public class BoundAdjacentCellIndexField : FieldBase<double>
        {
            public override ICellVarArr<double>? GetCellVarArr(IIndexHost indexHost)
            {
                return indexHost is FvBound b ?
                new BoundAdjacentCellIndexVars() { BouCFaces = b.InZone.BouFaces } :
                null;
            }
            public override IFaceVarArr<double>? GetFaceVarArr(IIndexHost indexHost)
            {
                return indexHost is FvBound b ?
                  new BoundAdjacentCellIndexVars() { BouCFaces = b.InZone.BouFaces } :
                  null;
            }
            protected class BoundAdjacentCellIndexVars : ICellVarArr<double>, IFaceVarArr<double>
            {
                public FvBouFace[] BouCFaces;
                public double GetCellVar(int cellID)
                {
                    return BouCFaces[cellID].OSideCell;
                }

                public double GetFaceVar(int faceID)
                {
                    return BouCFaces[faceID].OSideCell;
                }
            }
        }
        public class BoundAdjacentCellPressureField : FieldBase<double>
        {
            public override ICellVarArr<double>? GetCellVarArr(IIndexHost indexHost)
            {
                return get(indexHost);
            }
            public override IFaceVarArr<double>? GetFaceVarArr(IIndexHost indexHost)
            {
                return get(indexHost);
            }
            private BoundAdjacentCellPressureVars get(IIndexHost indexHost)
            {
                if (indexHost is FvBound b)
                {
                    double[] InnP = ResHelper.GetField(b.InZone)?.Pressure?.InnX;
                    if (InnP != null)
                    {
                        return new BoundAdjacentCellPressureVars()
                        {
                            BouCFaces = b.InZone.BouFaces,
                            InnP = InnP
                        };
                    }
                }
                return null;
            }
            protected class BoundAdjacentCellPressureVars : ICellVarArr<double>, IFaceVarArr<double>
            {
                public FvBouFace[] BouCFaces;
                public double[] InnP;

                public double GetCellVar(int cellID)
                {
                    return InnP[BouCFaces[cellID].OSideCell];
                }

                public double GetFaceVar(int faceID)
                {
                    return InnP[BouCFaces[faceID].OSideCell];
                }
            }
        }
    }
}
